package cn.yiiguxing.plugin.translate.trans.local.youdao

import cn.yiiguxing.plugin.translate.HTML_DESCRIPTION_TRANSLATOR_CONFIGURATION
import cn.yiiguxing.plugin.translate.message
import cn.yiiguxing.plugin.translate.trans.*
import cn.yiiguxing.plugin.translate.ui.settings.TranslationEngine.LOCALYOUDAO
import cn.yiiguxing.plugin.translate.util.*
import com.google.gson.Gson
import com.intellij.openapi.diagnostic.Logger
import com.intellij.util.io.HttpRequests
import java.util.*
import javax.swing.Icon
import kotlin.random.Random

@Suppress("SpellCheckingInspection")
object LocalYoudaoTranslator : AbstractTranslator() {

    private val SUPPORTED_LANGUAGES: List<Lang> = (Lang.sortedValues() - listOf(
        Lang.CHINESE_TRADITIONAL,
        Lang.CHINESE_CLASSICAL,
        Lang.AFRIKAANS,
        Lang.KYRGYZ,
        Lang.CATALAN,
        Lang.HMONG,
        Lang.SERBIAN,
        Lang.SLOVENIAN
    )).toList()

    private val logger: Logger = Logger.getInstance(LocalYoudaoTranslator::class.java)

    override val id: String = LOCALYOUDAO.id

    override val name: String = LOCALYOUDAO.translatorName

    override val icon: Icon = LOCALYOUDAO.icon

    override val intervalLimit: Int = LOCALYOUDAO.intervalLimit

    override val contentLengthLimit: Int = LOCALYOUDAO.contentLengthLimit

    override val defaultLangForLocale: Lang
        get() = when (Locale.getDefault()) {
            Locale.CHINA, Locale.CHINESE -> Lang.AUTO
            else -> super.defaultLangForLocale
        }

    override val primaryLanguage: Lang
        get() = LOCALYOUDAO.primaryLanguage

    override val supportedSourceLanguages: List<Lang> = SUPPORTED_LANGUAGES
    override val supportedTargetLanguages: List<Lang> = SUPPORTED_LANGUAGES

    override fun checkConfiguration(force: Boolean): Boolean {
        if (force || Settings.localYoudaoTranslateSettings.appId.isEmpty()) {
            return LOCALYOUDAO.showConfigurationDialog()
        }
        return true
    }

    override fun doTranslate(text: String, srcLang: Lang, targetLang: Lang): Translation {
        return SimpleTranslateClient(
            this,
            LocalYoudaoTranslator::call,
            LocalYoudaoTranslator::parseTranslation
        ).execute(
            text,
            srcLang,
            targetLang
        )
    }

    private fun call(
        text: String,
        srcLang: Lang,
        targetLang: Lang
    ): String {
        val settings = Settings.localYoudaoTranslateSettings
        val cookie = settings.appId
        val lts = System.currentTimeMillis();
        val salt = lts + Random(lts).nextDouble() * 10
        val userAgent =
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36";
        val bv = userAgent.md5();
        val tuner = HttpRequests.ConnectionTuner() {
            it.addRequestProperty("User-Agent", userAgent)
            it.addRequestProperty("Referer", "https://fanyi.youdao.com/");
            it.addRequestProperty("Cookie", cookie);
        }
        var client = "fanyideskweb";
        val sign = (client + text + salt + "Y2FYu%TNSbMCxc3t2u^XT").md5();
        return Http.postDataFrom2(
            "https://fanyi.youdao.com/translate_o",
            tuner,
            "i" to text,
            "from" to srcLang.localYoudaoLanguageCode,
            "to" to targetLang.localYoudaoLanguageCode,
            "client" to client,
            "salt" to salt.toString(),
            "sign" to sign,
            "lts" to lts.toString(),
            "bv" to bv,
            "doctype" to "json",
            "version" to "2.1",
            "keyfrom" to "fanyi.web",
            "action" to "FY_BY_CLICKBUTTION"
        )
    }

    @Suppress("UNUSED_PARAMETER")
    private fun parseTranslation(translation: String, original: String, srcLang: Lang, targetLang: Lang): Translation {
        logger.i("Translate result: $translation")
        return Gson().fromJson(translation, LocalYoudaoTranslation::class.java).apply {
            query = original
            checkError()
            if (!isSuccessful) {
                throw TranslateResultException(errorCode, name)
            }
        }.toTranslation()
    }

    override fun createErrorMessage(throwable: Throwable): String = when (throwable) {
        is TranslateResultException -> when (throwable.code) {
            101 -> message("error.missingParameter")
            102 -> message("error.language.unsupported")
            103 -> message("error.text.too.long")
            104 -> message("error.youdao.unsupported.api")
            105 -> message("error.youdao.unsupported.signature")
            106 -> message("error.youdao.unsupported.response")
            107 -> message("error.youdao.unsupported.encryptType")
            108 -> message("error.youdao.invalidKey", HTML_DESCRIPTION_TRANSLATOR_CONFIGURATION)
            109 -> message("error.youdao.batchLog")
            110 -> message("error.youdao.noInstance")
            111 -> message("error.invalidAccount", HTML_DESCRIPTION_TRANSLATOR_CONFIGURATION)
            201 -> message("error.youdao.decrypt")
            202 -> message("error.invalidSignature", HTML_DESCRIPTION_TRANSLATOR_CONFIGURATION)
            203 -> message("error.access.ip")
            301 -> message("error.youdao.dictionary")
            302 -> message("error.youdao.translation")
            303 -> message("error.youdao.serverError")
            401 -> message("error.account.has.run.out.of.balance")
            else -> message("error.unknown") + "[${throwable.code}]"
        }
        else -> super.createErrorMessage(throwable)
    }
}
